package com.YHVision.qiuzhike.controller;

import cn.dev33.satoken.annotation.SaCheckRole;
import cn.hutool.json.JSONUtil;
import com.YHVision.qiuzhike.model.dto.questionBankQuestion.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.YHVision.qiuzhike.annotation.AuthCheck;
import com.YHVision.qiuzhike.common.BaseResponse;
import com.YHVision.qiuzhike.common.DeleteRequest;
import com.YHVision.qiuzhike.common.ErrorCode;
import com.YHVision.qiuzhike.common.ResultUtils;
import com.YHVision.qiuzhike.constant.UserConstant;
import com.YHVision.qiuzhike.exception.BusinessException;
import com.YHVision.qiuzhike.exception.ThrowUtils;
import com.YHVision.qiuzhike.model.entity.QuestionBankQuestion;
import com.YHVision.qiuzhike.model.entity.User;
import com.YHVision.qiuzhike.model.vo.QuestionBankQuestionVO;
import com.YHVision.qiuzhike.service.QuestionBankQuestionService;
import com.YHVision.qiuzhike.service.UserService;
import com.jd.platform.hotkey.client.callback.JdHotKeyStore;
import io.grpc.internal.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxAccessToken;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 题库题目接口
 *
 * @author <a href="">YHVision-小y</a>
 * @from <a href="todo">爱编程学习圈</a>
 */
@RestController
@RequestMapping("/questionBankQuestion")
@Slf4j
public class QuestionBankQuestionController {

    @Resource
    private QuestionBankQuestionService questionBankQuestionService;

    @Resource
    private UserService userService;

    @Resource
    private RedisTemplate redisTemplate;

    // region 增删改查

    /**
     * 创建题库题目
     *
     * @param questionBankQuestionAddRequest
     * @param request
     * @return
     */
    @PostMapping("/add")
    public BaseResponse<Long> addQuestionBankQuestion(@RequestBody QuestionBankQuestionAddRequest questionBankQuestionAddRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(questionBankQuestionAddRequest == null, ErrorCode.PARAMS_ERROR);
        // todo 在此处将实体类和 DTO 进行转换
        QuestionBankQuestion questionBankQuestion = new QuestionBankQuestion();
        BeanUtils.copyProperties(questionBankQuestionAddRequest, questionBankQuestion);
        // 数据校验
        questionBankQuestionService.validQuestionBankQuestion(questionBankQuestion, true);
        // todo 填充默认值
        User loginUser = userService.getLoginUser(request);
        questionBankQuestion.setUserId(loginUser.getId());
        // 写入数据库
        boolean result = questionBankQuestionService.save(questionBankQuestion);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        // 返回新写入的数据 id
        long newQuestionBankQuestionId = questionBankQuestion.getId();
        return ResultUtils.success(newQuestionBankQuestionId);
    }

    /**
     * 删除题库题目
     *
     * @param deleteRequest
     * @param request
     * @return
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteQuestionBankQuestion(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User user = userService.getLoginUser(request);
        long id = deleteRequest.getId();
        // 判断是否存在
        QuestionBankQuestion oldQuestionBankQuestion = questionBankQuestionService.getById(id);
        ThrowUtils.throwIf(oldQuestionBankQuestion == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人或管理员可删除
        if (!oldQuestionBankQuestion.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        // 操作数据库
        boolean result = questionBankQuestionService.removeById(id);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }

    /**
     * 更新题库题目（仅管理员可用）
     *
     * @param questionBankQuestionUpdateRequest
     * @return
     */
    @PostMapping("/update")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updateQuestionBankQuestion(@RequestBody QuestionBankQuestionUpdateRequest questionBankQuestionUpdateRequest) {
        if (questionBankQuestionUpdateRequest == null || questionBankQuestionUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // todo 在此处将实体类和 DTO 进行转换
        QuestionBankQuestion questionBankQuestion = new QuestionBankQuestion();
        BeanUtils.copyProperties(questionBankQuestionUpdateRequest, questionBankQuestion);
        // 数据校验
        questionBankQuestionService.validQuestionBankQuestion(questionBankQuestion, false);
        // 判断是否存在
        long id = questionBankQuestionUpdateRequest.getId();
        QuestionBankQuestion oldQuestionBankQuestion = questionBankQuestionService.getById(id);
        ThrowUtils.throwIf(oldQuestionBankQuestion == null, ErrorCode.NOT_FOUND_ERROR);
        // 操作数据库
        boolean result = questionBankQuestionService.updateById(questionBankQuestion);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }

    /**
     * 根据 id 获取题库题目（封装类）
     *
     * @param id
     * @return
     */
    @GetMapping("/get/vo")
    public BaseResponse<QuestionBankQuestionVO> getQuestionBankQuestionVOById(long id, HttpServletRequest request) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);

        // 设置key
        String key = "bank_detail_" + id;
        // 判断是否是热key
        if (JdHotKeyStore.isHotKey(key)) {
            Object cachedQuestionBankVO = JdHotKeyStore.get(key);
            // 本地有缓存
            if (cachedQuestionBankVO != null) {
                return ResultUtils.success((QuestionBankQuestionVO) cachedQuestionBankVO);
            }

        }
        String redisValue = (String) redisTemplate.opsForValue().get(key);
        if (redisValue != null) {
            // 反序列化Redis中的数据
            QuestionBankQuestionVO redisCacheData = JSONUtil.toBean(redisValue, QuestionBankQuestionVO.class);

            // 回填本地缓存
            JdHotKeyStore.smartSet(key, redisCacheData);
            return ResultUtils.success(redisCacheData);
        }
        // 查询数据库
        QuestionBankQuestion questionBankQuestion = questionBankQuestionService.getById(id);
//        ThrowUtils.throwIf(questionBankQuestion == null, ErrorCode.NOT_FOUND_ERROR);
        // 获取封装类
        if (questionBankQuestion == null) {
            // 防止缓存穿透，设置空值缓存（短暂TTL）
            redisTemplate.opsForValue().set(key, "", 60, TimeUnit.SECONDS); // 设置空值缓存，TTL为60秒
            ThrowUtils.throwIf(true, ErrorCode.NOT_FOUND_ERROR);
        }
        QuestionBankQuestionVO questionBankQuestionVO = questionBankQuestionService.getQuestionBankQuestionVO(questionBankQuestion, request);
//        String lockKey = "lock:" + key;
//        boolean isLock = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 5, TimeUnit.SECONDS);
//        if (isLock) {
//            try {
//                // 查询数据库
//                QuestionBankQuestion questionBankQuestion = questionBankQuestionService.getById(id);
//                if (questionBankQuestion != null) {
//                    // 回填缓存
//                    redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(questionBankQuestion), 10, TimeUnit.MINUTES);
//                    return questionBankQuestion;
//                } else {
//                    // 数据不存在，缓存空值
//                    redisTemplate.opsForValue().set(key, "", 60, TimeUnit.SECONDS);
//                }
//            } finally {
//                // 释放锁
//                redisTemplate.delete(lockKey);
//            }
//        } else {
//            // 等待缓存构建完成
//            Thread.sleep(50); // 简单的等待策略
//            return JSONUtil.toBean(redisTemplate.opsForValue().get(key), QuestionBankQuestionVO.class);
//        }
        // 回填Redis缓存
        redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(questionBankQuestionVO), 10, TimeUnit.MINUTES); // 设置缓存10分钟


        // 设置缓存
        JdHotKeyStore.smartSet(key, questionBankQuestionVO);

        return ResultUtils.success(questionBankQuestionVO);
    }

    /**
     * 分页获取题库题目列表（仅管理员可用）
     *
     * @param questionBankQuestionQueryRequest
     * @return
     */
    @PostMapping("/list/page")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<QuestionBankQuestion>> listQuestionBankQuestionByPage(@RequestBody QuestionBankQuestionQueryRequest questionBankQuestionQueryRequest) {
        long current = questionBankQuestionQueryRequest.getCurrent();
        long size = questionBankQuestionQueryRequest.getPageSize();
        // 查询数据库
        Page<QuestionBankQuestion> questionBankQuestionPage = questionBankQuestionService.page(new Page<>(current, size),
                questionBankQuestionService.getQueryWrapper(questionBankQuestionQueryRequest));
        return ResultUtils.success(questionBankQuestionPage);
    }

    /**
     * 分页获取题库题目列表（封装类）
     *
     * @param questionBankQuestionQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/list/page/vo")
    public BaseResponse<Page<QuestionBankQuestionVO>> listQuestionBankQuestionVOByPage(@RequestBody QuestionBankQuestionQueryRequest questionBankQuestionQueryRequest,
                                                                                       HttpServletRequest request) {
        long current = questionBankQuestionQueryRequest.getCurrent();
        long size = questionBankQuestionQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        // 查询数据库
        Page<QuestionBankQuestion> questionBankQuestionPage = questionBankQuestionService.page(new Page<>(current, size),
                questionBankQuestionService.getQueryWrapper(questionBankQuestionQueryRequest));
        // 获取封装类
        return ResultUtils.success(questionBankQuestionService.getQuestionBankQuestionVOPage(questionBankQuestionPage, request));
    }

    /**
     * 分页获取当前登录用户创建的题库题目列表
     *
     * @param questionBankQuestionQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/my/list/page/vo")
    public BaseResponse<Page<QuestionBankQuestionVO>> listMyQuestionBankQuestionVOByPage(@RequestBody QuestionBankQuestionQueryRequest questionBankQuestionQueryRequest,
                                                                                         HttpServletRequest request) {
        ThrowUtils.throwIf(questionBankQuestionQueryRequest == null, ErrorCode.PARAMS_ERROR);
        // 补充查询条件，只查询当前登录用户的数据
        User loginUser = userService.getLoginUser(request);
        questionBankQuestionQueryRequest.setUserId(loginUser.getId());
        long current = questionBankQuestionQueryRequest.getCurrent();
        long size = questionBankQuestionQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        // 查询数据库
        Page<QuestionBankQuestion> questionBankQuestionPage = questionBankQuestionService.page(new Page<>(current, size),
                questionBankQuestionService.getQueryWrapper(questionBankQuestionQueryRequest));
        // 获取封装类
        return ResultUtils.success(questionBankQuestionService.getQuestionBankQuestionVOPage(questionBankQuestionPage, request));
    }

    /**
     * 移除题目题库关联表
     *
     * @param questionBankQuestionRemoveRequest
     * @return
     */
    @PostMapping("/remove")
    public BaseResponse<Boolean> removeQuestionBankQuestion(@RequestBody QuestionBankQuestionRemoveRequest questionBankQuestionRemoveRequest) {
        ThrowUtils.throwIf(questionBankQuestionRemoveRequest == null, ErrorCode.PARAMS_ERROR);
        //获取题目&题库id
        Long questionBankId = questionBankQuestionRemoveRequest.getQuestionBankId();
        Long questionId = questionBankQuestionRemoveRequest.getQuestionId();
        LambdaQueryWrapper<QuestionBankQuestion> lambdaQueryWrapper = Wrappers.lambdaQuery(QuestionBankQuestion.class)
                .eq(QuestionBankQuestion::getQuestionBankId, questionBankId)
                .eq(QuestionBankQuestion::getQuestionId, questionId);
        //操作数据库
        boolean rerult = questionBankQuestionService.remove(lambdaQueryWrapper);
        return ResultUtils.success(rerult);
    }

    /**
     * 批量添加题目到题库
     *
     * @param questionBankQuestionBatchAddQuestionRequest
     * @param request
     * @return
     */
    @PostMapping("/add/batch")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> batchAddQuestionToQuestionBank(@RequestBody QuestionBankQuestionBatchAddQuestionRequest questionBankQuestionBatchAddQuestionRequest,
                                                                HttpServletRequest request) {
        //数据校验
        ThrowUtils.throwIf(questionBankQuestionBatchAddQuestionRequest == null, ErrorCode.PARAMS_ERROR);
        //获取登录用户
        User loginUser = userService.getLoginUser(request);
        //操作数据库，获取题目列表id和题库id
        Long questionBankId = questionBankQuestionBatchAddQuestionRequest.getQuestionBankId();
        List<Long> questionIdList = questionBankQuestionBatchAddQuestionRequest.getQuestionIdList();
        //调用service批量添加题目到题库
        questionBankQuestionService.BatchAddQuestionsToQuestionBank(questionIdList, questionBankId, loginUser);
        //返回结果
        return ResultUtils.success(true);
    }

    /**
     * 批量移除题目从题库
     *
     * @param questionBankQuestionBatchRemoveQuestionRequest
     * @param request
     * @return
     */
    @PostMapping("/remove/batch")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> batchRemoveQuestionFromQuestionBank(@RequestBody QuestionBankQuestionBatchRemoveQuestionRequest questionBankQuestionBatchRemoveQuestionRequest,
                                                                     HttpServletRequest request) {
        //数据校验
        ThrowUtils.throwIf(questionBankQuestionBatchRemoveQuestionRequest == null, ErrorCode.PARAMS_ERROR);
        //操作数据库，获取题目列表id和题库id
        Long questionBankId = questionBankQuestionBatchRemoveQuestionRequest.getQuestionBankId();
        List<Long> questionIdList = questionBankQuestionBatchRemoveQuestionRequest.getQuestionIdList();
        //调用service批量添加题目到题库
        questionBankQuestionService.BatchRemoveQuestionsFromQuestionBank(questionIdList, questionBankId);
        //返回结果
        return ResultUtils.success(true);
    }


    // endregion
}
